package cz.muni.fi.pa165.web;

import cz.muni.fi.pa165.api.ForestVisitService;
import cz.muni.fi.pa165.api.MushroomService;
import cz.muni.fi.pa165.api.dto.ForestVisitDTO;
import cz.muni.fi.pa165.api.dto.MushroomDTO;
import cz.muni.fi.pa165.api.dto.MushroomDTO.Months;
import cz.muni.fi.pa165.api.dto.MushroomDTO.MushroomType;
import cz.muni.fi.pa165.web.validation.MushroomDTOEditValidator;
import cz.muni.fi.pa165.web.validation.MushroomDTOValidator;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

/**
 * Controller class for working with Mushroom
 *
 * @author Marek Tuharsky
 */
@Controller
public class MushroomController {

    @Autowired
    private MushroomService mushroomService;
    @Autowired
    private MushroomDTOValidator validator;
    @Autowired
    private MushroomDTOEditValidator editValidator;
    @Autowired
    private MessageSource messageSource;
    @Autowired
    private ForestVisitService forestVisitService;

    @RequestMapping(value = "auth/mushroom")
    public String initial(ModelMap modelMap) {
        modelMap.addAttribute("command", new MushroomDTO());
        modelMap.addAttribute("mushrooms", mushroomService.findAllMushrooms());
        return "auth/mushroom";
    }

    @RequestMapping(value = "auth/removeMushroom*")
    public String removeAdmin(@RequestParam("id") String request, ModelMap modelMap) {
        MushroomDTO mushroom = mushroomService.getMushroom(Long.valueOf(request));
        // remove mushroom from all forest visits
        for (ForestVisitDTO fv : forestVisitService.retrieveAllVisits()) {
            fv.getMushroomsFound().remove(mushroom);
            forestVisitService.updateVisit(fv);
        }
        mushroomService.removeMushroom(mushroom);
        modelMap.addAttribute("command", new MushroomDTO());
        modelMap.addAttribute("mushrooms", mushroomService.findAllMushrooms());
        return "auth/mushroom";
    }

    @RequestMapping(value = "auth/editMushroom*")
    public String editAdmin(@RequestParam("id") String request, ModelMap model) {
        MushroomDTO mushroom = mushroomService.getMushroom(Long.valueOf(request));
        model.addAttribute("command", mushroom);
        return "auth/editMushroom";
    }

    @RequestMapping(value = "auth/editedMushroom*")
    public String editedMushroomAdmin(@ModelAttribute("command") MushroomDTO mushroom,
            BindingResult result, ModelMap modelMap) {
        editValidator.validate(mushroom, result);
        if (result.hasErrors()) {
            modelMap.addAttribute("command", mushroom);
            return "auth/editMushroom";
        } else {
            mushroomService.updateMushroom(mushroom);
            modelMap.addAttribute("command", new MushroomDTO());
            modelMap.addAttribute("mushrooms", mushroomService.findAllMushrooms());
            return "auth/mushroom";
        }
    }

    @RequestMapping(value = "auth/addMushroom")
    public String add(@ModelAttribute("command") MushroomDTO mushroom, BindingResult result, ModelMap modelMap) {
        validator.validate(mushroom, result);
        if (result.hasErrors()) {
            modelMap.addAttribute("command", mushroom);
            modelMap.addAttribute("mushrooms", mushroomService.findAllMushrooms());
            return "auth/mushroom";
        } else {
            mushroomService.createMushroom(mushroom);
            modelMap.addAttribute("mushrooms", mushroomService.findAllMushrooms());
            return "auth/mushroom";
        }
    }

    @RequestMapping(value = "auth/mushroomSort*")
    public String sortMushrooms(@RequestParam("sortBy") String sortBy, ModelMap model) {
        if (sortBy.isEmpty()) {
            model.addAttribute("mushrooms", mushroomService.findAllMushrooms());
        }
        try {
            switch (sortBy) {
                case "EDIBLE":
                    model.addAttribute("mushrooms", mushroomService.findMushroomsByType(MushroomType.EDIBLE));
                    break;
                case "INEDIBLE":
                    model.addAttribute("mushrooms", mushroomService.findMushroomsByType(MushroomType.INEDIBLE));
                    break;
                case "POISONOUS":
                    model.addAttribute("mushrooms", mushroomService.findMushroomsByType(MushroomType.POISONOUS));
                    break;
                case "default":
                    model.addAttribute("mushrooms", mushroomService.findAllMushrooms());
            }
        } catch (Exception ex) {
            model.addAttribute("mushrooms", mushroomService.findAllMushrooms());
        }
        model.addAttribute("command", new MushroomDTO());
        return "auth/mushroom";
    }

    @ModelAttribute("items")
    public List<String> getTypes() {
        List<String> types = new ArrayList<>();
        for (MushroomType type : MushroomType.values()) {
            types.add(type.name());
        }
        return types;
    }

    @ModelAttribute("months")
    public List<String> getMonths() {
        List<String> months = new ArrayList<>();
        for (Months month : Months.values()) {
            months.add(month.name());
        }
        return months;
    }

    @ExceptionHandler(DataAccessException.class)
    public ModelAndView handleException(DataAccessException ex) {

        ModelAndView m = new ModelAndView();
        m.setViewName("mushroom");
        m.addObject("command", new MushroomDTO());
        m.addObject("mushrooms", mushroomService.findAllMushrooms());
        m.addObject("error", "Error has occured, try again");
        return m;
    }
}
